#include "thread_pool.h"
//主线程调用:处理客户端发过来的消息
void handleMessage(int sockfd, int epfd, task_queue_t * que)
{
    //消息格式：cmd content
    //1.1 获取消息长度
    int length = -1;
    int ret = recvn(sockfd, &length, sizeof(length));
    printf("\nrecv length: %d\n", length);

    //1.2 获取消息类型
    int cmdType = -1;
    ret = recvn(sockfd, &cmdType, sizeof(cmdType));
    printf("recv cmd type: %d\n", cmdType);
    task_t *ptask = (task_t*)calloc(1, sizeof(task_t));
    ptask->peerfd = sockfd;
    ptask->epfd = epfd;
    ptask->type= cmdType;
    //当发现是上传任务时，暂时从epoll中摘除
    if(ptask->type == CMD_TYPE_PUTS) {
        delEpollReadfd(epfd, sockfd);
    }
    if(length > 0) {
        //1.3 获取消息内容
        ret = recvn(sockfd, ptask->data, length);
        if(ret > 0) {
            //往线程池中添加任务
            printf("\n 1 taskque\n");
            taskEnque(que, ptask);
        }
    } else if(length == 0){
        printf("\n 2 taskque\n");
        taskEnque(que, ptask);
    }

    if(ret == 0) {//连接断开的情况
        printf("\nconn %d is closed.\n", sockfd);
        delEpollReadfd(epfd, sockfd);
        close(sockfd);
    }
}

void doTask(task_t * task)
{
    assert(task);
    switch(task->type) {
    case CMD_TYPE_PWD:  
        pwdCommand(task);   break;
    case CMD_TYPE_CD:
        cdCommand(task);    break;
    case CMD_TYPE_LS:
        lsCommand(task);    break;
    case CMD_TYPE_MKDIR:
        mkdirCommand(task);  break;
    case CMD_TYPE_RMDIR:
        rmdirCommand(task);  break;
    case CMD_TYPE_PUTS:
        putsCommand(task);  break;
    case CMD_TYPE_GETS:
        getsCommand(task);  break;
    case CMD_TYPE_NOTCMD:
        notCommand(task);   break;
    }
}

void pwdCommand(task_t * task)
{
    char cwd[256] = "";
    getcwd(cwd, sizeof(cwd));
    printf("%s\n", cwd);
}

void cdCommand(task_t * task)
{
    strtok(task->data, " ");
    char* token = strtok(task->data, " ");
    if(token){
        char cwd[1024] = "";
        if(getcwd(cwd, sizeof(cwd))!= NULL){
            char newDir[1024] = "";
            if(strcmp(token, "..") == 0){
                char* preDir = strrchr(cwd, '/');
                if(strcmp(preDir, "/server") == 0){
                    printf("访问越界\n");
                    return;
                }
                if(preDir){
                    *preDir = '\0';
                    strncpy(newDir, cwd, sizeof(newDir) - 1);
                }else{
                    return;
                }
            }else{
                if(token[0] == '/'){
                    strncpy(newDir, token, sizeof(newDir) - 1);
                }else{
                    snprintf(newDir, sizeof(newDir), "%s/%s", cwd, token);
                }
            }
            if(chdir(newDir) == 0)
                printf("execute cd command.\n");
        }
    }
}

void lsCommand(task_t * task)
{
    const char* path = ".";
    DIR *dir;
    struct dirent* entry;
    if((dir = opendir(path)) == NULL){
        error(1, errno, "opendir");
    }
    int num = 0;
    while((entry = readdir(dir)) != NULL){
        if(strcmp(entry->d_name, "..") == 0 ||strcmp(entry->d_name, ".") == 0 )
        {
            continue;
        }
        printf("%s\t", entry->d_name);
        num++;
        if(num == 5){
            num = 0;
            printf("\n");
        }
    }
    printf("\n");
    closedir(dir);
}

void mkdirCommand(task_t * task)
{
    const char* dir_name = strtok(task->data, " ");
    int ret = mkdir(dir_name, 0755);
    if(ret == -1){
        error(1, errno, "open");
    }
    printf("execute mkdir command.\n");
}

void deleteDir(const char* path)
{
    DIR* pdir = opendir(path);
    if(!pdir)
        error(1, errno, "opendir %s\n", path);

    errno = 0;
    struct dirent* curr;
    while((curr = readdir(pdir)) != NULL)
    {
        char *name = curr->d_name;
        if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
            continue;

        char subpath[256];
        sprintf(subpath, "%s/%s", path, name);
        if(curr->d_type == DT_DIR)
        {
            deleteDir(subpath);
        }else {
            unlink(subpath);
        }
    }
    if(errno)
    {
        error(1, errno, "readdir");
    }
    rmdir(path);
    closedir(pdir);
}
void rmdirCommand(task_t * task)
{
    char* path = strtok(task->data, " ");
    deleteDir(path);
    printf("execute rmdir command.\n");
}

void putsCommand(task_t* task)
{
    char buff[1000] = {0};
    int file_name_len = 0;
    int ret = recvn(task->peerfd, &file_name_len, sizeof(int));
    printf("file length:%d\n", file_name_len);
    recvn(task->peerfd, buff, file_name_len);
    if(strcmp(buff, "error") == 0)
    {
        printf("传输失败\n");
        addEpollReadfd(task->epfd, task->peerfd);
        return;
    }
    printf("filename: %s\n", buff);

    off_t lenth = 0;
    recvn(task->peerfd, &lenth, sizeof(off_t));
    printf("length: %ld\n", lenth);
    off_t currsize = 0;
    double percent = 0;

    int fd = open(buff, O_CREAT | O_RDWR, 0666);
    if(fd < 0){
        error(1, errno, "open");
    }
    while(1){
        memset(buff, 0, sizeof(buff));
        int file_len = 0;
        recvn(task->peerfd, &file_len, sizeof(int));
        if(file_len != 1000) {
            printf("len %d.\n", file_len);
        }
        ret = recvn(task->peerfd, buff, file_len);
        ret = write(fd, buff, strlen(buff));
        currsize += ret;
        percent = (double)currsize/lenth*100;
        printf("has complete %5.2lf%%\r", percent);
        if(ret < 1000){
            memset(buff, 0, sizeof(buff));
            break;
        }
        fflush(stdout);
    }
    printf("has complete %5.2lf%%\n", percent);
    //文件上传结束，将peerfd重新加回到epfd上进行监听
    addEpollReadfd(task->epfd, task->peerfd);
}

void getsCommand(task_t* task)
{
    if(strlen(task->data) == 0)
    {
        printf("无文件名\n");
        char errorfile[100] = "error";
        int len = strlen(errorfile);
        sendn(task->peerfd, &len, sizeof(int));
        sendn(task->peerfd, errorfile, strlen(errorfile));
        return;
    }
    char filename[100] = ""; 
    strcpy(filename, strtok(task->data, " "));
    transferFile(task->peerfd, filename);
}

void notCommand(task_t * task)
{
    printf("execute not command.\n");
}
